package de.koller.oceanFramework.math;

public class Interpolation {

	public static ISplineFunction interpolate( float yAt0, float yAt1, float mAt0, float mAt1 ) {
		return interpolateFunc( yAt0, yAt1, mAt0, mAt1 );
	}
	
	private static ISplineFunction interpolateFunc( final float y1, final float y2, final float t1, final float t2 ) {
		return new ISplineFunction() {
			@Override public float f( float x ) {
				return				( t1 + t2 + 2*y1 - 2*y2 )		* (x*x*x) +
									( -2*t1 - t2 - 3*y1 + 3*y2 )	* (x*x)   +
									t1								*  x	  +
									y1;
			}
		};
	}
	
	/** @param data [0] =  p00, [1] =  p10, [2] =  p11, [3] =  p01, 
	 *			[4] = t00x, [5] = t00y, [6] = t10x, [7] = t10y, 
	 *			[8] = t11x, [9] = t11y, [10] = t01x, [11] = t01y */
	public static ISplineFunction2D interpolateFunc2D( final float... data ) {
		return new ISplineFunction2D() {
			@Override public float f( float x, float y ) {
				float nt0y = linearAngle( x, data[5], data[7] );
				float nt1y = linearAngle( x, data[9], data[11] );
				float p0 = interpolateFunc( data[0], data[1], data[4], data[6] ).f( x );
				float p1 = interpolateFunc( data[3], data[2], data[10], data[8] ).f( x );
				
				return interpolateFunc( p0, p1, nt0y, nt1y ).f( y );
			}
		};
	}
	
	private static float linearAngle( float v, float st, float en ) {
		float sta = (float)Math.atan( st );
		float ena = (float)Math.atan( en );
		return (float)Math.tan( (ena-sta) * v + sta );
	}
	
	public static interface ISplineFunction {		
		public float f( float x );	
	}
	
	public static interface ISplineFunction2D {		
		public float f( float x, float y );	
	}
	
}
